import { listenFromTopic } from "@nodejs/mq"
import { loadProto, requestFromBuffer } from "./proto"
import { Message, RequestPayload, isErrorMessage, isMessage, isRequestMessage, isResponseMessage, isSendToMessage, isSendToRoomMessage } from "@core/types"
import { sendTo, sendToResponse, sendToRoom } from "./sendToResponse"
import { join } from "path"
import { parseJSON } from "@tools/core"
import { createLogger } from "@nodejs/logger"
import { useSecret, useToken } from "./utils"
import * as jwt from 'jsonwebtoken'
import os from 'os'
import { existsSync } from "fs-extra"
import { toError, toMessage, toReponse } from "./to"
export function listenRequestClientIdQueueFile(uuid: string, appName: string, root: string) {
    const homeDir = os.homedir()
    return listenRequestClientIdQueue(uuid, appName, async (msg: RequestPayload) => {
        try {
            let path = join(root, `${msg.path}.js`)
            if (!existsSync(path)) {
                path = join(homeDir, appName, `${msg.path}.js`)
            }
            const method = require(path).default;
            const data = parseJSON(msg.data.toString('utf8'))
            const headers = parseJSON(msg.headers.toString('utf8'))
            const logger = createLogger(appName)
            const token = useToken(data, headers)
            let user: any = { token };
            try {
                const secret = useSecret()
                const data = jwt.verify(token, secret)
                user = {
                    ...data,
                    ...user
                }
            } catch (e) { }
            // token 解析
            const result = await method(data, user, logger, msg)
            if (!result) {
                return;
            }
            if (isMessage(result)) {
                return result;
            } else {
                return toMessage(uuid, result, msg)
            }
        } catch (e) {
            const err: Error = e as any;
            return toError(uuid, err, msg)
        }
    })
}
export async function listenRequestClientIdQueue(uuid: string, appName: string, handler: (payload: RequestPayload) => Promise<Message<any> | undefined>) {
    const rootProto = await loadProto()
    return listenFromTopic(`request.topic`, `request.${appName}.${uuid}.queue`, `request.${appName}.${uuid}`, async (msg, channel) => {
        const request = requestFromBuffer(rootProto, msg.content)
        if (isRequestMessage(request)) {
            const payload = request.payload
            try {
                const response = await handler(payload)
                if (!response) {
                    channel.ack(msg);
                    return;
                }
                if (isMessage(response)) {
                    if (isResponseMessage(response)) {
                        await sendToResponse(rootProto, response.payload)
                    }
                    else if (isErrorMessage(response)) {
                        await sendToResponse(rootProto, response.payload)
                    }
                    else if (isSendToMessage(response)) {
                        await sendTo(rootProto, response.payload)
                    }
                    else if (isSendToRoomMessage(response)) {
                        await sendToRoom(rootProto, response.payload)
                    }
                } else {
                    await sendToResponse(rootProto, toReponse(uuid, response, {}, payload).payload)
                }
                channel.ack(msg)
                return;
            } catch (e) {
                const err: Error = e as any;
                await sendToResponse(rootProto, {
                    appid: payload.appid,
                    reqid: payload.reqid,
                    message: err.message,
                    stack: err.stack || '',
                    from: uuid,
                    data: Buffer.from(JSON.stringify({}))
                })
                channel.ack(msg)
                return;
            }
        }
    }, {
        durable: true
    })
}